package org.homonoia.worker.net;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.AbstractMap;
import java.util.AbstractMap.SimpleEntry;

import org.apache.log4j.Logger;
import org.homonoia.model.query.QueryID;
import org.homonoia.model.task.Task;
import org.homonoia.worker.core.WorkerNodeService;

public class SocketConnection implements Runnable {

    private final static Logger log = Logger.getLogger(SocketConnection.class);

    private WorkerNodeService workerNodeService = null;
    private Socket incomingSock = null;
    private BufferedReader in = null;

    public SocketConnection(Socket clientSock, WorkerNodeService workerNodeService) {
	this.workerNodeService = workerNodeService;
	this.incomingSock = clientSock;
    }

    public void run() {
	String request = null;

	try {
	    in = new BufferedReader(new InputStreamReader(incomingSock.getInputStream()));
	    request = in.readLine();

	    handleRequest(request);

	} catch (Exception e) {
	    log.error(e.getMessage(), e);
	}
    }

    private void handleRequest(final String request) {
	if (request.contains("status")) {
	    sendStatusUpdate();
	} else if (request.contains("task") && workerNodeService.checkForTask()) {
	    sendHeaderResponse("OK");
	    addNewTask();
	} else {
	    sendHeaderResponse("BAD REQUEST");
	}
    }

    private void sendHeaderResponse(final String response) {
	PrintWriter out = null;
	try {
	    out = new PrintWriter(incomingSock.getOutputStream(), true);
	    out.println("Accept: " + response);
	} catch (IOException e) {
	    log.error(e.getMessage(), e);
	}
    }

    private void sendStatusUpdate() {
	PrintWriter out = null;

	try {
	    out = new PrintWriter(incomingSock.getOutputStream());
	    out.println("Status: " + workerNodeService.getStatus().toString().toUpperCase());
	} catch (IOException e) {
	    log.error(e.getMessage(), e);
	}
    }

    @SuppressWarnings("unchecked")
    private void addNewTask() {
	ObjectInputStream ois = null;
	AbstractMap.SimpleEntry<QueryID, Task> pair = null;

	try {
	    ois = new ObjectInputStream(incomingSock.getInputStream());
	    pair = (SimpleEntry<QueryID, Task>) ois.readObject();
	} catch (ClassNotFoundException e) {
	    log.error(e.getMessage(), e);
	} catch (IOException e) {
	    log.error(e.getMessage(), e);
	} finally {
	    try {
		if (incomingSock != null) {
		    incomingSock.close();
		}
	    } catch (IOException e) {
	    }
	}

	if (pair != null) {
	    workerNodeService.addNewTask(pair.getKey(), pair.getValue());
	}
    }

}
